#include <string.h>
#include "gkt_debug.h"
#include "gkt_malloc.h"
#include "gkt_board.h"
#include "g_sha.h"
//#include "crypto_defines.h"
//#include "crypto_regs.h"
#if 0
static int crypto_sha_padding(crypto_params_s *params)
{
	uint32_t len_field_bytes, unalign_len, pad_len;
	uint32_t aligned_len, total_bits;
	uint8_t *aligned_message;
	
	len_field_bytes = params->block_size >> 3;

	unalign_len = params->input_len & (params->block_size - 1);
	pad_len = params->block_size - unalign_len;
	if (pad_len <= len_field_bytes)
		pad_len += params->block_size;

	aligned_len = params->input_len + pad_len;
	aligned_message = (uint8_t *)gkt_malloc(aligned_len);
	if (!aligned_message) {
		gkt_error("crypto_sha_padding: alloc aligned message failed!\n");
		return GKT_ENOMEMORY;
	}

	memcpy(aligned_message, params->input_data, params->input_len);
	memset(&aligned_message[params->input_len], 0, pad_len);
	if (pad_len > len_field_bytes)
		aligned_message[params->input_len] = 0x80;

	total_bits = params->input_len << 3;
	while (total_bits) {
		pad_len--;
		aligned_message[params->input_len + pad_len] = total_bits & 0xff;
		total_bits >>= 8;
	}

	params->input_data = aligned_message;
	params->input_len = aligned_len;

	return GKT_SUCCESS;
}

static int crypto_sha(crypto_params_s *params)
{
	crypto_instance_s *instance;
	uint32_t base_addr, reg_value, timeout;
	int retval;

	gkt_trace("crypto_sha: algo(%u), message(%p @ %u)\n",
				params->algo_type, params->input_data, 
				params->input_len);

	if (!params->input_data 
		|| !params->input_len
		|| !params->output_data
		|| (params->input_data == params->output_data))
	{
		return GKT_EPARAM;
	}

	instance = crypto_request_instance(params);
	if (__UNLIKELY(!instance))
		return GKT_ENORESOURCE;
	base_addr = CRYPTO_BASEADDR(CRYPTO_DEVID(instance));

	retval = crypto_sha_padding(params);
	if (retval != GKT_SUCCESS)
		goto release_instance;

	gkt_trace("crypto_sha: padding - message(%p @ %u)\n",
				params->input_data, params->input_len);

	/* clear semaphore */
	while (GKT_SUCCESS == gkt_semaphore_acquire(instance->semaphore, 0));
	instance->result = GKT_EUNKNOWN;

	gkt_clkrst_enable_clock(CRYPTO_CLKRST_DESC(CRYPTO_DEVID(instance)));

	reg_value = (params->action << CRYPTO_ACTION_SHIFT)
				| (CRYPTO_DATA_BIG_ENDIAN << CRYPTO_OUTPUT_DATA_ENDIAN_SHIFT)
				| (CRYPTO_DATA_BIG_ENDIAN << CRYPTO_INPUT_DATA_ENDIAN_SHIFT)
				| (CRYPTO_KEY_FROM_REG << CRYPTO_KEY_SRC_SHIFT);
	gkt_write_reg32(base_addr + CRYPTO_CONTROL0, reg_value);

	reg_value = (CRYPTO_DMA_TRANS_MODE_4 << CRYPTO_DMA_TRANS_MODE_SHIFT)
				| (params->algo_type << CRYPTO_ALGO_TYPE_SHIFT);
	gkt_write_reg32(base_addr + CRYPTO_CONTROL1, reg_value);

	gkt_write_reg32(base_addr + CRYPTO_MSG_SIZE, params->input_len);

	retval = crypto_dma_start(instance);
	if (retval != GKT_SUCCESS)
		goto disable_clock;
	crypto_irq_config(base_addr, CRYPTO_FINISH_INTERRUPT);
	crypto_enable(base_addr);

	timeout = (params->input_len / params->block_size) * CRYPTO_BLOCK_TIMEOUT;
	retval = gkt_semaphore_acquire(instance->semaphore, timeout);
	if (__LIKELY(GKT_SUCCESS == retval))
		retval = instance->result;

	crypto_disable_interrupt(base_addr, CRYPTO_ALL_INTERRUPT);
	crypto_dma_stop(instance);
	crypto_disable(base_addr);

disable_clock:
	gkt_clkrst_disable_clock(CRYPTO_CLKRST_DESC(CRYPTO_DEVID(instance)));
	gkt_free((void *)((uint32_t)params->input_data));
release_instance:
	crypto_release_instance(instance);

	return retval;
}
#endif

#if defined(GKT_CRYPTO_SHA1_SUPPORT) && GKT_CRYPTO_SHA1_SUPPORT
int gkt_crypto_sha1(const uint8_t *message, 
			uint32_t msg_len, uint8_t *digest)
{
	SHA(SHATYPE_1, digest, (uint8_t *)message, msg_len);
	return GKT_SUCCESS;
}
#endif

#if defined(GKT_CRYPTO_SHA256_SUPPORT) && GKT_CRYPTO_SHA256_SUPPORT
int gkt_crypto_sha256(const uint8_t *message, 
			uint32_t msg_len, uint8_t *digest)
{
	SHA(SHATYPE_256, digest, (uint8_t *)message, msg_len);
	return GKT_SUCCESS;
}
#endif

